/*
 * Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
 *
 * Licensed under the Mulan PSL v2.
 * You can use this file according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of the License at
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
 * FOR MORE DETAILS.
 */

#pragma once

#include <thread>
#include <typeinfo>

SG_DBMANAGER_NAMESPACE_OPEN

template <typename T>
bool CachePool::Put (const std::string& key, T* data, std::chrono::milliseconds ttl, std::function<void (T*)> destructor)
{
    if (!data)
    {
        return false;
    }

    std::lock_guard<std::mutex> lock (m_mutex);

    // 如果键已存在，先移除旧项
    auto it = m_cache.find (key);
    if (it != m_cache.end ())
    {
        FreeItem (it->second->metadata);
        m_lruList.erase (it->second);
        m_cache.erase (it);
    }

    // 创建新节点
    m_lruList.emplace_front (key);
    auto nodeIt = m_lruList.begin ();

    // 设置元数据
    auto now                        = std::chrono::steady_clock::now ();
    nodeIt->metadata.createTime     = now;
    nodeIt->metadata.lastAccessTime = now;
    nodeIt->metadata.ttl            = ttl;
    nodeIt->metadata.memorySize     = CalculateMemorySize (data);
    nodeIt->metadata.dataPtr        = static_cast<void*> (data);
    nodeIt->metadata.typeName       = typeid (T).name ();

    // 设置销毁函数
    if (destructor)
    {
        nodeIt->metadata.destructor = [destructor] (void* ptr) { destructor (static_cast<T*> (ptr)); };
    }
    else
    {
        nodeIt->metadata.destructor = CreateDestructor<T> ();
    }

    // 更新内存使用量
    m_currentMemorySize += nodeIt->metadata.memorySize;

    // 添加到哈希表
    m_cache[key] = nodeIt;

    // 检查容量限制（使用内部版本，避免重复加锁）
    EnforceCapacityLimitsInternal ();

    return true;
}

template <typename T>
T* CachePool::Get (const std::string& key)
{
    std::lock_guard<std::mutex> lock (m_mutex);

    auto it = m_cache.find (key);
    if (it == m_cache.end ())
    {
        return nullptr;
    }

    auto& metadata = it->second->metadata;

    // 快速检查：如果TTL为0（永不过期），跳过过期检查
    if (metadata.ttl.count () != 0)
    {
        // 只有在有TTL的情况下才进行过期检查
        auto now     = std::chrono::steady_clock::now ();
        auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds> (now - metadata.createTime);
        
        if (elapsed >= metadata.ttl)
        {
            // 已过期，清理并返回nullptr
            FreeItem (metadata);
            m_lruList.erase (it->second);
            m_cache.erase (it);
            return nullptr;
        }
        
        // 更新访问时间（复用已获取的时间）
        metadata.lastAccessTime = now;
    }
    else
    {
        // 对于永不过期的项目，仍需更新访问时间，但只在必要时获取时间
        metadata.lastAccessTime = std::chrono::steady_clock::now ();
    }

    // 优化：只有当节点不在头部时才移动
    if (it->second != m_lruList.begin ())
    {
        m_lruList.splice (m_lruList.begin (), m_lruList, it->second);
    }

    return static_cast<T*> (metadata.dataPtr);
}

template <typename T>
T* CachePool::GetFast (const std::string& key)
{
    std::lock_guard<std::mutex> lock (m_mutex);

    auto it = m_cache.find (key);
    if (it == m_cache.end ())
    {
        return nullptr;
    }

    auto& metadata = it->second->metadata;

    // 快速路径：跳过过期检查，仅更新访问时间
    metadata.lastAccessTime = std::chrono::steady_clock::now ();

    // 优化：只有当节点不在头部时才移动
    if (it->second != m_lruList.begin ())
    {
        m_lruList.splice (m_lruList.begin (), m_lruList, it->second);
    }

    return static_cast<T*> (metadata.dataPtr);
}

template <typename T>
std::size_t CachePool::CalculateMemorySize (const T* container)
{
    if (!container)
    {
        return 0;
    }

    std::size_t size = sizeof (T);

    // 简化的内存计算，主要估算容器本身加上元素大小
    // 如果容器有size()方法，估算元素占用的内存
    try
    {
        auto containerSize = container->size ();
        if (containerSize > 0)
        {
            // 为不同容器类型提供基本的内存估算
            size += containerSize * sizeof (typename T::value_type);

            // 为map类容器额外计算key的大小
            if (typeid (T).name () != nullptr)
            {
                std::string typeName = typeid (T).name ();
                if (typeName.find ("map") != std::string::npos && typeName.find ("unordered") == std::string::npos)
                {
                    // 这是map类型，需要额外空间存储节点指针
                    size += containerSize * sizeof (void*) * 3;  // 左、右、父节点指针
                }
                else if (typeName.find ("unordered") != std::string::npos)
                {
                    // 这是hash容器，需要额外的桶空间
                    size += 16 * sizeof (void*);  // 估算的桶数量
                }
            }
        }
    }
    catch (...)
    {
        // 如果容器没有size()方法或出现异常，只返回基本大小
    }

    return size;
}

template <typename T>
std::function<void (void*)> CachePool::CreateDestructor ()
{
    return [] (void* ptr) { delete static_cast<T*> (ptr); };
}

SG_DBMANAGER_NAMESPACE_CLOSE
